﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using System.Threading;

namespace Topro.Service
{
    using NLog;
    using System.Text.RegularExpressions;
    using Topro.Application;
    using Topro.Entity;
    using Topro.Entity.Query;
    using Topro.Enum;
    using Topro.Libraries.Util;
    using Topro.Monitor;
    using Topro.Util;

    public class AppTwoService
    {
        #region 变量
        /// <summary>
        /// 消息委托
        /// </summary>
        public delegate void InfoDelegate(int type, Dictionary<string, string> dc);

        /// <summary>
        /// 消息事件
        /// </summary>
        public event InfoDelegate infoEvent;

        /// <summary>
        /// 站台消息委托
        /// </summary>
        public delegate void StationDelegate(int station, int status);

        /// <summary>
        /// 站台消息事件
        /// </summary>
        public event StationDelegate stationEvent;

        /// <summary>
        /// 堆垛
        /// </summary>
        public TwoStacker stacker = null;

        /// <summary>
        /// 出入库站台
        /// </summary>
        public List<StockStation> stockStations = null;

        /// <summary>
        /// 入库暂存站台
        /// </summary>
        public List<InStockStation> inStockStations = null;

        /// <summary>
        /// 出库暂存站台
        /// </summary>
        public List<OutStockStation> outStockStations = null;

        /// <summary>
        /// moxa线程
        /// </summary>
        private Thread moxaThread = null;

        /// <summary>
        /// 读码器
        /// </summary>
        public List<BCRStation> bcrStations = null;

        /// <summary>
        /// 
        /// </summary>
        private List<TcpClientUtil> tcpClientUtils = null;

        /// <summary>
        /// 日志
        /// </summary>
        private static readonly Logger log = LogManager.GetLogger("Scan");
        #endregion

        #region 初始化
        public void init()
        {
            #region 异常
            var deviceExceptionCodeListQuery = new DeviceExceptionCodeListQuery()
            {
                MachineCode = 1
            };
            var deviceExceptionCode = DeviceExceptionCodeApp.Instance.GetList(deviceExceptionCodeListQuery);

            infoEvent(0, new Dictionary<string, string> { ["1"] = $"二号垛机异常数({deviceExceptionCode.Count})" });
            #endregion

            #region 读码器
            //获取指令列有
            string bcrStationFilePath = $"{System.Environment.CurrentDirectory}\\BCRStation.xml";
            //获取xml内容
            var outInStationXml = Libraries.Util.FileUtil.loadFile(bcrStationFilePath);
            //序列化
            bcrStations = Libraries.Util.SerializationUtil.XmlDeserialize<List<BCRStation>>(outInStationXml);
            #endregion

            //获取指令列有
            string stockStationPath = $"{System.Environment.CurrentDirectory}\\TwoStockStation.xml";
            //获取xml内容
            var stockStationXml = Libraries.Util.FileUtil.loadFile(stockStationPath);
            //序列化
             stockStations = Libraries.Util.SerializationUtil.XmlDeserialize<List<StockStation>>(stockStationXml);

            stacker = new TwoStacker();
            stacker.stockStations = stockStations.Distinct(c=>c.Id).ToList();
            stacker.inStockStations = stockStations.Where(c => c.Type == (int)WorkStatus.One).ToList();
            stacker.outStockStations = stockStations.Where(c => c.Type == (int)WorkStatus.Two).ToList();
            stacker.deviceExceptionCode = deviceExceptionCode;
            stacker.infoEvent += new TwoStacker.InfoDelegate(Info);
            stacker.stationEvent += new TwoStacker.StationDelegate(Station);
            stacker.stackerStationNumber = int.Parse(ConfigurationManager.AppSettings["stackerTwoStationNumber"]);

            //输送线
            stacker.transLineStationNumber = int.Parse(ConfigurationManager.AppSettings["transLineStationNumber"]);

            if (stacker.transLineUtil == null)
                stacker.transLineUtil = new PlcUtil(stacker.transLineStationNumber);

            if (stacker.transLineUtil.connectStatus == ConnectStatus.Opened)
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"二号输送线({stacker.transLineStationNumber})启动成功" });
            else
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"二号输送线({stacker.transLineStationNumber})启动失败" });
            //堆垛机
            if (stacker.stackerUtil == null)
                stacker.stackerUtil = new PlcUtil(stacker.stackerStationNumber);
            if (stacker.stackerUtil.connectStatus == ConnectStatus.Opened)
            {
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"二号堆垛机({stacker.stackerStationNumber})启动成功" });
                stacker.stackerThread = new Thread(stacker.main);
                stacker.stackerThread.IsBackground = true;
                stacker.stackerThread.Start();
            }
            else
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"二号堆垛机({stacker.stackerStationNumber})启动失败" });

            #region 扫码
            moxaThread = new Thread(moxa);
            moxaThread.Start();
            #endregion
        }
        #endregion

        #region 设置入口
        /// <summary>
        /// 设置出入口
        /// </summary>
        /// <param name="commandId">指令编号</param>
        /// <param name="stationNo">站号</param>
        /// <param name="resourceId">容器编码</param>
        public JResult SetInStation(int commandId, int qrCode)
        {
            var response = new JResult()
            {
                Success = false
            };

            try
            {
                //验证堆垛机对象是否为空
                //if (oneStacker == null)
                //    infoEvent(0, new Dictionary<string, string> { ["1"] = $"堆垛机对象为空." });
                //清除入栈流水号
                inStockStations.ForEach(item =>
                {
                    if (commandId == item.Id)
                    {
                        //var status = stacker.SetTransLineSingleData(item.SerialNoAddr, qrCode);
                        //if (status == 0)
                        //{
                        //    throw new Exception($"设置出入库站台流水号{item.SerialNoAddr}->{qrCode}成功.");
                        //}
                    }
                });
            }
            catch (Exception ex)
            {
                response.Message = ex.Message;
            }

            return response;
        }
        #endregion

        #region 清除出入口
        /// <summary>
        /// 清除出入口
        /// </summary>
        public void ClearOutInStation()
        {
            //if (!stacker.Any())
            //    infoEvent(0, new Dictionary<string, string> { ["1"] = $"堆垛机对象为空." });
            ////清除出入口条码
            //bcrStations.ForEach(item =>
            //{
            //    bcrStations.FirstOrDefault(c => c.Id == item.Id).BarCode = "0000";
            //});

            ////清除
            //inStockStations.ForEach(item =>
            //{
            //    stackers.ForEach(stacker => {
            //        //stacker.SetSingleData(item.SerialNoAddr, 0);
            //    });
            //});

            //if (bcrStations != null && bcrStations.Any())
            //    infoEvent(100, bcrStations.ToDictionary(item => item.Id.ToString(), item => item.BarCode));
        }
        #endregion

        #region 扫码器
        /// <summary>
        /// 初始化扫码器
        /// </summary>
        public void moxa()
        {
            tcpClientUtils = new List<TcpClientUtil>();

           // var bcrStationList = bcrStations.Where(c => new List<int>() { 10 }.Contains(c.Id)).ToList();
            var bcrStationList = bcrStations.Where(c => new List<int>() { 10 }.Contains(c.Id)).ToList();

            if (bcrStationList != null && bcrStationList.Any())
            {
                foreach (var item in bcrStationList)
                {
                    var tcpClientUtil = new TcpClientUtil(item.ServerIp, item.ServerProt);
                    //委托
                    tcpClientUtil.MessageEvent += new TcpClientUtil.MessageDelegate(Scan);

                    tcpClientUtils.Add(tcpClientUtil);

                    infoEvent(0, new Dictionary<string, string> { ["1"] = $"读码器({item.Id}->{item.ServerIp}->{item.ServerProt})连接成功." });
                }
            }
        }

        /// <summary>
        /// 获取扫码
        /// </summary>
        /// <param name="_tPackMes"></param>
        public void Scan(string message)
        {
            try
            {
                if (!string.IsNullOrEmpty(message))
                {
                    log.Info($"[扫码][{message}]");

                    if (message == "ConSuccessful")
                    {
                        return;
                    }

                    //扫码转换为数量、
                    var array = message.Split(':');
                    //验证数组大小
                    if (array.Length != 2)
                    {
                        log.Info($"格式有误.");

                        return;
                    }

                    //验证无记录
                    if (array[1] == "ERROR")
                    {
                        log.Info($"无记录..");

                        return;
                    }
                    //编号
                    var id = 0;
                    //转换
                    int.TryParse(Regex.Replace(array[0], @"[\r\n]", ""), out id);
                    //容器
                    string qrCode = Regex.Replace(array[1], @"[\r\n]", "");

                    //设置
                    var stockStation = stockStations.FirstOrDefault(c => c.Id == id);
                    if (stockStation != null)
                    {
                        infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][自动设置流水号({stockStation.SerialNoAddr}->{id})]" });

                        if (stacker.transLineUtil != null)
                        {
                            int result = stacker.transLineUtil.Set(stockStation.SerialNoAddr, id);
                            if (result == -1)
                                infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][设置流水号失败]" });
                            else
                                infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][设置站台流水号成功]" });
                        }
                        else
                            infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][输送线对象为空]" });
                    }
                    else
                        infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][站台获取失败]" });
                }
                else
                    infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][获取托盘码内容为空]" });
            }
            catch (Exception ex)
            {
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][扫码异常:{ex.Message}]" });
            }
        }
        #endregion

        #region 设置站号
        /// <summary>
        /// 设置站号
        /// </summary>
        /// <param name="stationId">站号</param>
        public void SetStation(int stationId, int containerCode)
        {
            stacker.SetStation(stationId, containerCode);
        }
        #endregion

        #region 事件消息
        /// <summary>
        /// 事件消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="workStatus"></param>
        /// <param name="info"></param>
        public void Info(int type, Dictionary<string, string> dc)
        {
            if (infoEvent != null)
                infoEvent(type, dc);
        }

        /// <summary>
        /// 站台事件消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="workStatus"></param>
        /// <param name="info"></param>
        public void Station(int station, int status)
        {
            if (stationEvent != null)
                stationEvent(station, status);
        }

        /// <summary>
        /// 站台事件消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="workStatus"></param>
        /// <param name="info"></param>
        public void TwoStation(int station, int status)
        {
            if (stationEvent != null)
                stationEvent(station, status);
        }
        #endregion

        #region 重新执行
        /// <summary>
        /// 重新执行
        /// </summary>
        public JResult ReRun(int id)
        {
            return null;
            //return oneStacker.ReRun(id);
        }
        #endregion

        #region 复原
        /// <summary>
        /// 复原
        /// </summary>
        /// <returns></returns>
        public JResult Restore()
        {
            return stacker.Restore();
        }
        #endregion

        #region 释放
        /// <summary>
        /// 释放
        /// </summary>
        public void close()
        {

            if (stacker != null)
            {
                if (stacker.stackerThread != null)
                    stacker.stackerThread.Abort();

                stacker.Dispose();
            }
        }
        #endregion

        #region 清空
        /// <summary>
        /// 清空
        /// </summary>
        /// <returns></returns>
        public JResult Clear()
        {
            return null;
            //return oneStacker.Clear();
        }
        #endregion
    }
}
